package com.cantor.core.handler;

import com.cantor.common.serializer.Serializer;
import com.cantor.core.message.CantorMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 不可共享的编解码器
 */
@Slf4j
public class CantorMessageCodec extends ByteToMessageCodec<CantorMessage> {

    /**
     * 协议头设计如下:
     * magicNum 魔数 4字节
     * sequenceId 分布式请求ID 8字节
     * version 协议版本 1字节
     * serializationType 序列化方式 4字节
     * messageType 业务消息类型 4字节
     * skip 无意义对齐字节 1字节
     * len 一个完整包的长度字段长度 4字节
     *
     * 共: 26字节
     */

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, CantorMessage message, ByteBuf byteBuf) throws Exception {
        log.trace("[序列化] {}",message);
        // 写头
        byteBuf.writeBytes(message.getMagicNum());
        byteBuf.writeLong(message.getSequenceId());
        byteBuf.writeByte(message.getVersion());
        byteBuf.writeInt(message.getSerializationType());
        byteBuf.writeInt(message.getMessageType());
        byteBuf.writeByte(0xff);
        Serializer serializer = Serializer.allSerializers.get(message.getSerializationType());
        byte[] bytes = serializer.serialize(message);
        byteBuf.writeInt(bytes.length);
        // 写正文
        byteBuf.writeBytes(bytes);
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception {
        log.trace("[反序列化] {}");
        // 读头
        byte[] magicNum = new byte[4];
        byteBuf.readBytes(magicNum);
        long sequenceId = byteBuf.readLong();
        byte version = byteBuf.readByte();
        int serializationType = byteBuf.readInt();
        int messageType = byteBuf.readInt();
        byteBuf.readByte();
        int len = byteBuf.readInt();
        // 读正文
        byte[] bytes = new byte[len];
        byteBuf.readBytes(bytes);
        Serializer serializer = Serializer.allSerializers.get(serializationType);
        CantorMessage message = serializer.deserialize(bytes, CantorMessage.class);
        list.add(message);
    }
}
